/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef ICM_DRV_H
#define ICM_DRV_H

/*!
 * @file icm_drv.h
 * @brief This file declares icm driver interfaces
 */

/*!
 * @addtogroup icm_drv
 * @{
 */

/*******Includes***************************************************************/
#include <stdint.h>
#include <stdbool.h>
#include "stdio.h"
#include "errcodes.h"
#include "device_registers.h"

/*******Definitions************************************************************/

/*!
 * @brief ADC trigger source
 */
typedef enum {
#if (CONFIG_ICM_SUPPORT_SPWM2_TRIGGER == 0U)
    ICM_TRIGGER_GND = 0U,           /*!< GND*/
    ICM_SPWM0_MAX_TRIGGER,          /*!< SPWM0 max trigger sel */
    ICM_SPWM0_MIN_TRIGGER,          /*!< SPWM0 min trigger sel */
    ICM_SPWM0_MATCH_TRIGGER,        /*!< SPWM0 match trigger sel */
    ICM_SPWM1_MAX_TRIGGER,          /*!< SPWM1 max trigger sel */
    ICM_SPWM1_MIN_TRIGGER,          /*!< SPWM1 min trigger sel */
    ICM_SPWM1_MATCH_TRIGGER,        /*!< SPWM1 match trigger sel */
    ICM_IPWM0_MAX_TRIGGER,          /*!< IPWM0 max trigger sel */
    ICM_IPWM0_MIN_TRIGGER,          /*!< IPWM0 min trigger sel */
    ICM_IPWM0_MATCH_TRIGGER,        /*!< IPWM0 match trigger sel */
    ICM_IPWM1_MAX_TRIGGER,          /*!< IPWM1 max trigger sel */
    ICM_IPWM1_MIN_TRIGGER,          /*!< IPWM1 min trigger sel */
    ICM_IPWM1_MATCH_TRIGGER,        /*!< IPWM1 min trigger sel */
    ICM_CMP_OUTPUT,                 /*!< CMP output sel */
    ICM_TIMER0_OVERFLOW,            /*!< TIMER0 overflow sel */
    ICM_TIMER1_OVERFLOW,            /*!< TIMER1 overflow sel */
    ICM_RTC_ALARM_TRIGGER,          /*!< RTC alarm trigger sel */
    ICM_RTC_PERIODIC_ALARM_TRIGGER  /*!< RTC periodic alarm trigger sel */
#else
    ICM_TRIGGER_GND = 0U,           /*!< GND*/
    ICM_SPWM0_MAX_TRIGGER,          /*!< SPWM0 max trigger sel */
    ICM_SPWM0_MIN_TRIGGER,          /*!< SPWM0 min trigger sel */
    ICM_SPWM0_MATCH_TRIGGER,        /*!< SPWM0 match trigger sel */
    ICM_SPWM1_MAX_TRIGGER,          /*!< SPWM1 max trigger sel */
    ICM_SPWM1_MIN_TRIGGER,          /*!< SPWM1 min trigger sel */
    ICM_SPWM1_MATCH_TRIGGER,        /*!< SPWM1 match trigger sel */
    ICM_SPWM2_MAX_TRIGGER,          /*!< SPWM2 max trigger sel */
    ICM_SPWM2_MIN_TRIGGER,          /*!< SPWM2 min trigger sel */
    ICM_SPWM2_MATCH_TRIGGER,        /*!< SPWM2 match trigger sel */
    ICM_IPWM0_MAX_TRIGGER,          /*!< IPWM0 max trigger sel */
    ICM_IPWM0_MIN_TRIGGER,          /*!< IPWM0 min trigger sel */
    ICM_IPWM0_MATCH_TRIGGER,        /*!< IPWM0 match trigger sel */
    ICM_IPWM1_MAX_TRIGGER,          /*!< IPWM1 max trigger sel */
    ICM_IPWM1_MIN_TRIGGER,          /*!< IPWM1 min trigger sel */
    ICM_IPWM1_MATCH_TRIGGER,        /*!< IPWM1 min trigger sel */
    ICM_CMP_OUTPUT,                 /*!< CMP output sel */
    ICM_TIMER0_OVERFLOW,            /*!< TIMER0 overflow sel */
    ICM_TIMER1_OVERFLOW,            /*!< TIMER1 overflow sel */
    ICM_TIMER2_OVERFLOW,            /*!< TIMER0 overflow sel */
    ICM_TIMER3_OVERFLOW,            /*!< TIMER1 overflow sel */
    ICM_RTC_ALARM_TRIGGER,          /*!< RTC alarm trigger sel */
    ICM_RTC_PERIODIC_ALARM_TRIGGER  /*!< RTC periodic alarm trigger sel */
#endif
} icm_adc_trigger_source_t;

/*!
 * @brief ADC normal channel trigger target
 */
typedef enum {
    ICM_ADC0_NORMAL_CHANNEL_TRIGGER_SEL0 = 0U, /*!< ADC0 normal channel trigger sel0 */
    ICM_ADC0_NORMAL_CHANNEL_TRIGGER_SEL1 = 1U, /*!< ADC0 normal channel trigger sel1 */
    ICM_ADC0_NORMAL_CHANNEL_TRIGGER_SEL2 = 2U, /*!< ADC0 normal channel trigger sel2 */
    ICM_ADC0_NORMAL_CHANNEL_TRIGGER_SEL3 = 3U, /*!< ADC0 normal channel trigger sel3 */
#if (CONFIG_ICM_SUPPORT_SPWM2_TRIGGER == 1U)
    ICM_ADC1_NORMAL_CHANNEL_TRIGGER_SEL0 = 4U, /*!< ADC1 normal channel trigger sel0 */
    ICM_ADC1_NORMAL_CHANNEL_TRIGGER_SEL1 = 5U, /*!< ADC1 normal channel trigger sel1 */
    ICM_ADC1_NORMAL_CHANNEL_TRIGGER_SEL2 = 6U, /*!< ADC1 normal channel trigger sel2 */
    ICM_ADC1_NORMAL_CHANNEL_TRIGGER_SEL3 = 7U  /*!< ADC1 normal channel trigger sel3 */
#endif
} icm_adc_normal_channel_trigger_target_t;

/*!
 * @brief ADC priority channel trigger target
 */
typedef enum {
    ICM_ADC0_PRIORITY_CHANNEL_TRIGGER_SEL0 = 0U,   /*!< ADC0 priority channel trigger sel0 */
    ICM_ADC0_PRIORITY_CHANNEL_TRIGGER_SEL1 = 1U,   /*!< ADC0 priority channel trigger sel1 */
    ICM_ADC0_PRIORITY_CHANNEL_TRIGGER_SEL2 = 2U,   /*!< ADC0 priority channel trigger sel2 */
    ICM_ADC0_PRIORITY_CHANNEL_TRIGGER_SEL3 = 3U,   /*!< ADC0 priority channel trigger sel3 */
#if (CONFIG_ICM_SUPPORT_SPWM2_TRIGGER == 1U)
    ICM_ADC1_PRIORITY_CHANNEL_TRIGGER_SEL0 = 4U,   /*!< ADC1 priority channel trigger sel0 */
    ICM_ADC1_PRIORITY_CHANNEL_TRIGGER_SEL1 = 5U,   /*!< ADC1 priority channel trigger sel1 */
    ICM_ADC1_PRIORITY_CHANNEL_TRIGGER_SEL2 = 6U,   /*!< ADC1 priority channel trigger sel2 */
    ICM_ADC1_PRIORITY_CHANNEL_TRIGGER_SEL3 = 7U    /*!< ADC1 priority channel trigger sel3 */
#endif
} icm_adc_priority_channel_trigger_target_t;

/*!
 * @brief SPWM fault source
 */
typedef enum {
#if (CONFIG_ICM_SUPPORT_SPWM2_TRIGGER == 0U)
    ICM_FAULT_GND = 0U,                    /*!< Fault source is GND */
    ICM_FAULT_ADC_ANALOG_WATCHDOG = 1U,    /*!< Fault source is ADC analog watchdog event */
    ICM_FAULT_CMP_OUTPUT = 2U              /*!< Fault source is CMP output */
#else
    ICM_FAULT_GND = 0U,                    /*!< Fault source is GND */
    ICM_FAULT_CMP_OUTPUT = 1U,             /*!< Fault source is CMP output */
    ICM_FAULT_ADC0_ANALOG_WATCHDOG = 2U,   /*!< Fault source is ADC0 analog watchdog event */
    ICM_FAULT_ADC1_ANALOG_WATCHDOG = 3U    /*!< Fault source is ADC1 analog watchdog event */
#endif
} icm_spwm_fault_source_t;

/*!
 * @brief SPWM fault target
 */
typedef enum {
    ICM_SPWM0_FAULT2 = 0U,   /*!< SPWM0 fault source2 */
    ICM_SPWM0_FAULT3 = 1U,   /*!< SPWM0 fault source3 */
    ICM_SPWM1_FAULT2 = 2U,   /*!< SPWM1 fault source2 */
    ICM_SPWM1_FAULT3 = 3U,   /*!< SPWM1 fault source3 */
#if (CONFIG_ICM_SUPPORT_SPWM2_TRIGGER == 1U)
    ICM_SPWM2_FAULT2 = 4U,   /*!< SPWM2 fault source2 */
    ICM_SPWM2_FAULT3 = 5U    /*!< SPWM2 fault source3 */
#endif
} icm_spwm_fault_target_t;

/*!
 * @brief SPWM sync target
 */
typedef enum {
    ICM_SPWM0_SYNC0 = 0U,       /*!< SPWM0 hardware sync target0 */
    ICM_SPWM0_SYNC1 = 1U,       /*!< SPWM0 hardware sync target1 */
    ICM_SPWM1_SYNC0 = 2U,       /*!< SPWM1 hardware sync target0 */
    ICM_SPWM1_SYNC1 = 3U,       /*!< SPWM1 hardware sync target1 */
#if (CONFIG_ICM_SUPPORT_SPWM2_TRIGGER == 1U)
    ICM_SPWM2_SYNC0 = 4U,       /*!< SPWM2 hardware sync target0 */
    ICM_SPWM2_SYNC1 = 5U        /*!< SPWM2 hardware sync target1 */
#endif
} icm_spwm_sync_target_t;

/*!
 * @brief SPWM sync source
 */
typedef enum {
    ICM_SPWM_SYNC_CMP_OUTPUT = 0U,      /*!< SPWM hardware sync source is CMP output */
    ICM_SPWM_SYNC_IPWM0_CH3 = 1U        /*!< SPWM hardware sync source is IPWM0_CH3 */
} icm_spwm_sync_source_t;

/*!
 * @brief CMP output trigger target
 */
typedef enum {
    ICM_CMP_OUTPUT_TO_IPWM0_CH0 = 0U,   /*!< CMP ouput to IPWM0_CH0 */
    ICM_CMP_OUTPUT_TO_IPWM0_CH1 = 1U,   /*!< CMP ouput to IPWM0_CH1 */
    ICM_CMP_OUTPUT_TO_IPWM0_CH2 = 2U,   /*!< CMP ouput to IPWM0_CH2 */
    ICM_CMP_OUTPUT_TO_IPWM0_CH3 = 3U,   /*!< CMP ouput to IPWM0_CH3 */
    ICM_CMP_OUTPUT_TO_IPWM1_CH0 = 4U,   /*!< CMP ouput to IPWM1_CH0 */
    ICM_CMP_OUTPUT_TO_IPWM1_CH1 = 5U,   /*!< CMP ouput to IPWM1_CH1 */
    ICM_CMP_OUTPUT_TO_IPWM1_CH2 = 6U,   /*!< CMP ouput to IPWM1_CH2 */
    ICM_CMP_OUTPUT_TO_IPWM1_CH3 = 7U    /*!< CMP ouput to IPWM1_CH3 */
} icm_cmp_output_trigger_target_t;

/*!
 * @brief CMP output trigger target
 */
typedef enum {
    ICM_CONNECT_PAD = 0U,           /*!< CMP ouput trigger target0 */
    ICM_CMP_PARALLEL_OUTPUT = 1U,   /*!< CMP ouput trigger target1 */
    ICM_CMP_SERIAL_OUTPUT = 2U      /*!< CMP ouput trigger target2 */
} icm_cmp_output_source_t;

/*!
 * @brief SPWM capture CMP parallel output target
 */
typedef enum {
    ICM_SPWM0_CAPTURE = 0U,   /*!< CMP ouput capture by SPWM0 */
    ICM_SPWM1_CAPTURE = 1U,   /*!< CMP ouput capture by SPWM1 */
#if (CONFIG_ICM_SUPPORT_SPWM2_TRIGGER == 1U)
    ICM_SPWM2_CAPTURE = 2U    /*!< CMP ouput capture by SPWM2 */
#endif
} icm_spwm_capture_pos_target_t;

/*!
 * @brief CMP window source select
 */
typedef enum {
    ICM_WINDOW_IPWM0_CH0 = 0U,   /*!< CMP select IPWM0_CH0 as window */
    ICM_WINDOW_IPWM0_CH1 = 1U,   /*!< CMP select IPWM0_CH1 as window */
    ICM_WINDOW_IPWM0_CH2 = 2U,   /*!< CMP select IPWM0_CH2 as window */
    ICM_WINDOW_IPWM0_CH3 = 3U    /*!< CMP select IPWM0_CH3 as window */
} icm_cmp_window_source_t;

/*******APIs*******************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief ADC normal channel trigger source select
 *
 * @param[in] instance: The ICM peripheral instance number
 * @param[in] triggerTarget: ADC normal channel trigger target
 *            - 0: ICM_ADC0_NORMAL_CHANNEL_TRIGGER_SEL0
 *            - 1: ICM_ADC0_NORMAL_CHANNEL_TRIGGER_SEL1
 *            - 2: ICM_ADC0_NORMAL_CHANNEL_TRIGGER_SEL2
 *            - 3: ICM_ADC0_NORMAL_CHANNEL_TRIGGER_SEL3
 *            - 4: ICM_ADC1_NORMAL_CHANNEL_TRIGGER_SEL0
 *            - 5: ICM_ADC1_NORMAL_CHANNEL_TRIGGER_SEL1
 *            - 6: ICM_ADC1_NORMAL_CHANNEL_TRIGGER_SEL2
 *            - 7: ICM_ADC1_NORMAL_CHANNEL_TRIGGER_SEL3
 * @param[in] triggerSource: ADC trigger source
 * @return None
 */
void ICM_SetTriggerSourceForADCNormalChannel(uint32_t instance,
                                             icm_adc_normal_channel_trigger_target_t triggerTarget,
                                             icm_adc_trigger_source_t triggerSource);

/*!
 * @brief ADC priority channel trigger source select
 *
 * @param[in] instance: The ICM peripheral instance number
 * @param[in] triggerTarget: ADC priority channel trigger target
 *            - 0: ICM_ADC0_PRIORITY_CHANNEL_TRIGGER_SEL0
 *            - 1: ICM_ADC0_PRIORITY_CHANNEL_TRIGGER_SEL1
 *            - 2: ICM_ADC0_PRIORITY_CHANNEL_TRIGGER_SEL2
 *            - 3: ICM_ADC0_PRIORITY_CHANNEL_TRIGGER_SEL3
 *            - 4: ICM_ADC1_PRIORITY_CHANNEL_TRIGGER_SEL0
 *            - 5: ICM_ADC1_PRIORITY_CHANNEL_TRIGGER_SEL1
 *            - 6: ICM_ADC1_PRIORITY_CHANNEL_TRIGGER_SEL2
 *            - 7: ICM_ADC1_PRIORITY_CHANNEL_TRIGGER_SEL3
 * @param[in] triggerSource: ADC trigger source
 * @return None
 */
void ICM_SetTriggerSourceForADCPriorityChannel(uint32_t instance,
                                               icm_adc_priority_channel_trigger_target_t triggerTarget,
                                               icm_adc_trigger_source_t triggerSource);

/*!
 * @brief SPWM fault source select
 *
 * @param[in] instance: The ICM peripheral instance number
 * @param[in] faultTarget: SPWM fault target
 *            - 0: ICM_SPWM0_FAULT2
 *            - 1: ICM_SPWM0_FAULT3
 *            - 2: ICM_SPWM1_FAULT2
 *            - 3: ICM_SPWM1_FAULT3
 *            - 4: ICM_SPWM2_FAULT2
 *            - 5: ICM_SPWM2_FAULT3
 * @param[in] faultSource: SPWM fault source
 *            - 0: ICM_FAULT_GND
 *            - 1: ICM_ADC_ANALOG_WATCHDOG
 *            - 2: ICM_ACMP_OUTPUT
 * @return None
 */
void ICM_SetSPWMFaultSource(uint32_t instance,
                            icm_spwm_fault_target_t faultTarget,
                            icm_spwm_fault_source_t faultSource);

/*!
 * @brief SPWM hardware sync source enable
 *
 * @param[in] instance: The ICM peripheral instance number
 * @param[in] syncTarget: SPWM sync target
 *            - 0: ICM_SPWM0_SYNC0
 *            - 1: ICM_SPWM0_SYNC1
 *            - 2: ICM_SPWM1_SYNC0
 *            - 3: ICM_SPWM1_SYNC1
 *            - 4: ICM_SPWM2_SYNC0
 *            - 5: ICM_SPWM2_SYNC1
 * @param[in] enable
 *            - true: Enable
 *            - false: Disable
 * @return None
 */
void ICM_SetSPWMHardwareSyncSourceEn(uint32_t instance, icm_spwm_sync_target_t syncTarget, bool enable);

/*!
 * @brief SPWM0 modulation enable
 *
 * @param[in] instance: The ICM peripheral instance number
 * @param[in] channelMsk: SPWM0 CH0~7 modulation enable mask
 * @return None
 */
void ICM_SetSPWM0Modulation(uint32_t instance, uint8_t channelMsk);

/*!
 * @brief SPWM1 modulation enable
 *
 * @param[in] instance: The ICM peripheral instance number
 * @param[in] channelMsk: SPWM1 CH0~7 modulation enable mask
 * @return None
 */
void ICM_SetSPWM1Modulation(uint32_t instance, uint8_t channelMsk);

/*!
 * @brief CMP parallel output capture by SPWM enable
 *
 * @param[in] instance: The ICM peripheral instance number
 * @param[in] target: CMP parallel output capture by spwm target
 *            - 0: ICM_SPWM0_CAPTURE
 *            - 1: ICM_SPWM1_CAPTURE
 *            - 2: ICM_SPWM2_CAPTURE
 * @param[in] enable
 *            - true: Enable
 *            - false: Disable
 * @return None
 */
void ICM_SetSPWMCapturePOSEn(uint32_t instance,
                             icm_spwm_capture_pos_target_t target,
                             bool enable);

/*!
 * @brief Set IPWM capture source and capture target from CMP
 *
 * @param[in] instance: The ICM peripheral instance number
 * @param[in] target: IPWM capture target
 *            - 0: ICM_IPWM0_CH0_CAPTURE
 *            - 1: ICM_IPWM0_CH1_CAPTURE
 *            - 2: ICM_IPWM0_CH2_CAPTURE
 *            - 3: ICM_IPWM0_CH3_CAPTURE
 *            - 4: ICM_IPWM1_CH0_CAPTURE
 *            - 5: ICM_IPWM1_CH1_CAPTURE
 *            - 6: ICM_IPWM1_CH2_CAPTURE
 *            - 7: ICM_IPWM1_CH3_CAPTURE
 * @param[in] source: IPWM capture source
 *            - 0: ICM_CONNECT_PAD
 *            - 1: ICM_CMP_PARALLEL_OUTPUT
 *            - 2: ICM_CMP_SERIAL_OUTPUT
 * @return None
 */
void ICM_SetIPWMCaptureSource(uint32_t instance,
                              icm_cmp_output_trigger_target_t target,
                              icm_cmp_output_source_t source);

/*!
 * @brief RTC clock capture enable
 *
 * @param[in] instance: The ICM peripheral instance number
 * @param[in] enable
 *            - true: RTC clock capture enable
 *            - false: RTC clock capture disable
 * @return None
 */
void ICM_SetRTCClockCaptureEn(uint32_t instance, bool enable);

/*!
 * @brief LSI capture enable
 *
 * @param[in] instance: The ICM peripheral instance number
 * @param[in] enable
 *            - true: LSI capture enable
 *            - false: LSI capture disable
 * @return None
 */
void ICM_SetLSICaptureEn(uint32_t instance, bool enable);

/*!
 * @brief CMP window source select
 *
 * @param[in] instance: The ICM peripheral instance number
 * @param[in] source: CMP window source
 *            - 0: ICM_WINDOW_IPWM0_CH0
 *            - 1: ICM_WINDOW_IPWM0_CH1
 *            - 2: ICM_WINDOW_IPWM0_CH2
 *            - 3: ICM_WINDOW_IPWM0_CH3
 * @return None
 */
void ICM_SetCMPWindow(uint32_t instance, icm_cmp_window_source_t source);

/*!
 * @brief Init ICM
 *
 * @param[in] instance: The ICM peripheral instance number
 * @return None
 */
void ICM_Init(uint32_t instance);

/*!
 * @brief Deinit ICM
 *
 * @param[in] instance: The ICM peripheral instance number
 * @return None
 */
void ICM_Deinit(uint32_t instance);

#if defined(__cplusplus)
}
#endif

/*! @} */

#endif /* ICM_DRV_H */

/*******EOF********************************************************************/

